package com.padakeji.android.ui.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.padakeji.android.ui.R;

/**
 * Created by AtanL on 15/3/14.
 */
public class PinnedHeaderListView extends ExpandableListView {

	private PinnedHeaderListAdapter mAdapter;

    private View mHeaderView;
    private int mHeaderGroupPos = -1;
    private int mHeaderMeasuredWidth;
    private int mHeaderMeasuredHeight;
    private int mHeaderOffsetY;

    private int dividerHeight;

    private OnScrollListener mOnScrollListener;
	private OnGroupClickListener mOnGroupClickListener;

    private boolean alwaysExpanded = true;

	/**
	 * http://developer.android.com/training/custom-views/create-view.html
	 * 
	 * @param context
	 */
	public PinnedHeaderListView(Context context) {
		super(context);
		init();
	}

	public PinnedHeaderListView(Context context, AttributeSet attrs) {
		this(context, attrs, R.attr.pinnedHeaderListViewStyle);
	}

	public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		TypedArray a = context.getTheme().obtainStyledAttributes(
				attrs,
				R.styleable.PinnedHeaderListView,
				defStyleAttr, R.style.DefaultPinnedHeaderListViewStyle);
		try {
			alwaysExpanded = a.getBoolean(R.styleable.PinnedHeaderListView_alwaysExpanded, true);
		} finally {
			a.recycle();
		}

		Log.d("PinnedHeaderListView", alwaysExpanded + "");
		init();
	}

	private void init() {
		dividerHeight = getDividerHeight();
		super.setOnScrollListener(new MyOnScrollListener());
		super.setOnGroupClickListener(new MyOnGroupClickListener());
	}

	
	/**
	 * This overloaded method should not be used, instead use
	 * {@link #setAdapter(PinnedHeaderListAdapter)}. Or nothing will be done but
	 * throw runtime exception.
	 * <p>
	 * {@inheritDoc}
	 */
	@Override
	public void setAdapter(ListAdapter adapter) {
		throw new RuntimeException(
				"For ExpandableListView, use setAdapter(PinnedHeadListAdapter) instead of "
						+ "setAdapter(ListAdapter)");
	}

	
	/**
	 * This overloaded method should not be used, instead use
	 * {@link #setAdapter(PinnedHeaderListAdapter)}. Or nothing will be done but
	 * throw runtime exception.
	 * <p>
	 * {@inheritDoc}
	 */
	@Override
	public void setAdapter(ExpandableListAdapter adapter) {
		throw new RuntimeException(
				"For PinnedHeadListView, use setAdapter(PinnedHeadListAdapter) instead of "
						+ "setAdapter(ExpandableListAdapter)");
	}

	/**
	 * Sets the adapter that provides data to this view.
	 * 
	 * @param adapter The adapter that provides data to this view.
	 */
	public void setAdapter(PinnedHeaderListAdapter adapter) {
		this.mAdapter = adapter;
		super.setAdapter(adapter);
	}

	
	
	@Override
	public ListAdapter getAdapter() {
		/*
		 * The developer should never really call this method on an
		 * ExpandableListView, so it would be nice to throw a RuntimeException,
		 * but AdapterView calls this
		 */
		return super.getAdapter();
	}

	/**
	 * This method should not be used, use {@link #getExpandableListAdapter()}.
	 */
	public ExpandableListAdapter getExpandableListAdapter() {
		return super.getExpandableListAdapter();
	}
	
	
	public PinnedHeaderListAdapter getPinnedHeaderListAdapter() {
		return mAdapter;
	}
	

	/**
	 * Notice: 
	 * <p>
	 * This overloaded method is final, so it can't be override any more. Please override {@link #onDispatchDraw(Canvas)} instead.
	 * <p>
	 * 
	 * {@inheritDoc}
	 * 
	 */
	@Override
	final protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (mAdapter == null || mHeaderView == null) {
			return;
		}
		int saveCount = canvas.save();
		canvas.translate(0, mHeaderOffsetY);
		canvas.clipRect(0, 0, mHeaderMeasuredWidth, mHeaderMeasuredHeight); // needed
		drawChild(canvas, mHeaderView, getDrawingTime());
		canvas.restoreToCount(saveCount);

		onDispatchDraw(canvas);
	}
	
	
	/**
	 * Instead of overriding {@link #dispatchDraw(Canvas)}, please override this method to perform dispatching works. 
	 * 
	 * @param canvas
	 */
	protected void onDispatchDraw(Canvas canvas) {
		
	}
	
	
	/**
	 * Notice: 
	 * <p>
	 * This overloaded method is final, so it can't be override any more. Please override {@link #onDispatchTouchEvent(MotionEvent)} instead.
	 * <p>
	 * 
	 * {@inheritDoc}
	 */
	@Override
	final public boolean dispatchTouchEvent(MotionEvent ev) {
		if (mHeaderView != null) {
			float touchX = ev.getX();
			float touchY = ev.getY();
			if (touchX <= mHeaderMeasuredWidth && touchY <= mHeaderMeasuredHeight + mHeaderOffsetY) {
				switch (ev.getAction()) {
				case MotionEvent.ACTION_UP:
					if (mOnGroupClickListener == null || !mOnGroupClickListener.onGroupClick(this, mHeaderView, mHeaderGroupPos, mAdapter.getGroupId(mHeaderGroupPos))) {
						if (expandGroup(mHeaderGroupPos) || collapseGroup(mHeaderGroupPos));
					}
					break;
				default:
					break;
				}
				return true;
			}
		}
		
		return onDispatchTouchEvent(ev);
	}

	/**
	 * Instead of overriding {@link #dispatchTouchEvent(MotionEvent)}, please override this method to perform dispatching works. 
	 * 
	 * @param ev
	 * @return
	 */
	public boolean onDispatchTouchEvent(MotionEvent ev) {
		return super.dispatchTouchEvent(ev);
	}
	
	
	@Override
	public void setOnScrollListener(OnScrollListener l) {
		this.mOnScrollListener = l;
	}
	
	
	@Override
	public void setOnGroupClickListener(OnGroupClickListener onGroupClickListener) {
		this.mOnGroupClickListener = onGroupClickListener;
	}

	
	private class MyOnGroupClickListener implements OnGroupClickListener {
		@Override
		public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
			if (mOnGroupClickListener != null) {
				return mOnGroupClickListener.onGroupClick(parent, v, groupPosition, id);
			}
			return false;
		}
		
	}
	
	private int mWidthMeasureSpec;
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		mWidthMeasureSpec = widthMeasureSpec;
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	
	
	private class MyOnScrollListener implements OnScrollListener {

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) {
			if (mOnScrollListener != null) {
				mOnScrollListener.onScrollStateChanged(view, scrollState);
			}
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
			if (mOnScrollListener != null) {
				mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
			}
			
			
			long packedPosition = getExpandableListPosition(firstVisibleItem);
			int groupPosition = getPackedPositionGroup(packedPosition);

			if (groupPosition < 0) {
				mHeaderView = null;
				mHeaderGroupPos = -1;
				return;
			}
			
			if (groupPosition != mHeaderGroupPos) {
				mHeaderGroupPos = groupPosition;
				mHeaderView = mAdapter.getGroupView(groupPosition, mAdapter.isGroupExpanded(groupPosition), null, PinnedHeaderListView.this);

				AbsListView.LayoutParams params = (AbsListView.LayoutParams) mHeaderView.getLayoutParams();
		        if(params == null) {
		            params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0);
		            mHeaderView.setLayoutParams(params);
		        }
		        final int mHeaderWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getPaddingLeft() + getPaddingRight(), params.width);
		        final int paramsHeight = params.height;
		        int mHeaderHeightSpec;
		        if(paramsHeight > 0) {
					mHeaderHeightSpec = MeasureSpec.makeMeasureSpec(paramsHeight, MeasureSpec.EXACTLY);
		        } else {
					mHeaderHeightSpec = MeasureSpec.makeMeasureSpec(0 , MeasureSpec.UNSPECIFIED);
		        }
		        mHeaderView.measure(mHeaderWidthSpec, mHeaderHeightSpec);

				mHeaderMeasuredWidth = mHeaderView.getMeasuredWidth();
				mHeaderMeasuredHeight = mHeaderView.getMeasuredHeight();

				mHeaderView.layout(0, 0, mHeaderMeasuredWidth, mHeaderMeasuredHeight);
			}
			
			mHeaderOffsetY = 0;
			int i;
			for (i = firstVisibleItem + 1; i < firstVisibleItem	+ visibleItemCount; ++i) {
				long cursorPackedPosition = getExpandableListPosition(i);
				int cursorGroupPosition = getPackedPositionGroup(cursorPackedPosition);
				if (cursorGroupPosition != groupPosition) {
					View cursorGroupView = getChildAt(i - firstVisibleItem);
					int headerTop = cursorGroupView.getTop();
					if (headerTop < mHeaderMeasuredHeight + dividerHeight) {
						mHeaderOffsetY = headerTop - (mHeaderMeasuredHeight + dividerHeight);
					}
					break;
				}
			}
			

			invalidate();
			requestLayout();

		}
	}

	public boolean isAlwaysExpanded() {
		return alwaysExpanded;
	}

	public void setAlwaysExpanded(boolean alwaysExpanded) {
		this.alwaysExpanded = alwaysExpanded;
		invalidate();
		requestLayout();
	}
}
